-------------------模块区-------------------
local dx_json = require("dx_json")
local dx_gpio = require("dx_gpio")
local t_permission = require("t_permission")
local t_passrecord = require("t_passrecord")
local log = require("mylog")
local dx_bit = require("dx_bit")
local dx_map = require("dx_map")
local dx_mapping = require("mapping")
local config = require("config")
local time = require("time")
local os_util = require("os_util")
local dx_download_util = require("download_util")
local string_util = require("string_util")


-------------------变量区-------------------
-- 继电器
GPIO_70 = 70
local mqtt_service = {}

-- 初始化读取配置信息
local device_addr = config.get("uuid")
log.info("device_addr" .. device_addr)

-- 订阅消息topic表
mqtt_service.subscribe = {
    -- -- 配置查询查询
    CMD_TOPIC_GETCONFIG = "20220316/cmd/" .. device_addr .. "/getConfig",
    -- -- 配置修改
    CMD_TOPIC_SETCONFIG = "20220316/cmd/" .. device_addr .. "/setConfig",
    -- -- 查询权限
    CMD_TOPIC_GETPERMSSION = "20220316/cmd/" .. device_addr .. "/getPermission",
    -- -- 添加权限
    CMD_TOPIC_INSERTPERMISSION = "20220316/cmd/" .. device_addr .. "/insertPermission",
    -- -- 删除权限
    CMD_TOPIC_DELPERMISSION = "20220316/cmd/" .. device_addr .. "/delPermission",
    -- -- 清空权限
    CMD_TOPIC_CLEARPERMISSION = "20220316/cmd/" .. device_addr .. "/clearPermission",
    -- -- 修改权限（预留）
    CMD_TOPIC_UPDATEPERMISSION = "20220316/cmd/" .. device_addr .. "/updatePermission",
    -- -- 远程控制
    CMD_TOPIC_CONTROLDEVICE = "20220316/cmd/" .. device_addr .. "/control",
    -- -- 升级固件
    CMD_TOPIC_UPGRADEFIRMWARE = "20220316/cmd/" .. device_addr .. "/upgradeFirmware",
    -- 连接上报回调
    EVENT_TOPIC_CONNECT_REPLY = "20220316/event/" .. device_addr .. "/connect_reply",
    -- 告警上报回调
    EVENT_TOPIC_ALARM_REPLY = "20220316/event/" .. device_addr .. "/alarm_reply",
    -- 通行上报回调
    EVENT_TOPIC_ACCESS_REPLY = "20220316/event/" .. device_addr .. "/access_reply",
    -- 日志上报回调
    EVENT_TOPIC_LOG_REPLY = "20220316/event/" .. device_addr .. "/log_reply"
}

-- 发布消息topic表
mqtt_service.publish = {
    -- -- 配置查询回调
    CMD_TOPIC_GETCONFIG_REPLY = "20220316/cmd/getConfig_reply",
    -- -- 配置修改回调
    CMD_TOPIC_SETCONFIG_REPLY = "20220316/cmd/setConfig_reply",
    -- -- 查询权限回调
    CMD_TOPIC_GETPERMSSION_REPLY = "20220316/cmd/getPermission_reply",
    -- -- 添加权限回调
    CMD_TOPIC_INSERTPERMISSION_REPLY = "20220316/cmd/insertPermission_reply",
    -- -- 删除权限回调
    CMD_TOPIC_DELPERMISSION_REPLY = "20220316/cmd/delPermission_reply",
    -- -- 清空权限回调
    CMD_TOPIC_CLEARPERMISSION_REPLY = "20220316/cmd/clearPermission_reply",
    -- -- 修改权限回调（预留）
    CMD_TOPIC_UPDATEPERMISSION_REPLY = "20220316/cmd/updatePermission_reply",
    -- -- 远程控制回调
    CMD_TOPIC_CONTROLDEVICE_REPLY = "20220316/cmd/control_reply",
    -- -- 升级固件回调
    CMD_TOPIC_UPGRADEFIRMWARE_REPLY = "20220316/cmd/upgradeFirmware_reply",
    -- 连接上报
    EVENT_TOPIC_CONNECT = "20220316/event/connect",
    -- 告警上报
    EVENT_TOPIC_ALARM = "20220316/event/alarm",
    -- 通行上报
    EVENT_TOPIC_ACCESS = "20220316/event/access",
    -- 日志上报
    EVENT_TOPIC_LOG = "20220316/event/log"
}

-- 将发布的topic设为全局，以便回调使用
_G.publish_topics = mqtt_service.publish


-------------------函数区-------------------
-- 远程控制
function mqtt_service.control(payload)
    local ret, data, source_payload = payload_validate(payload)
    if not ret then
        return false
    end

    source_payload.data = {
        command = data.command
    }

    -- 0：重启 1：远程开门 2：设备启用 3：设备禁用 4：设备重置
    if data.command == 0 then
        source_payload.code = "000000"
        callback_common(publish_topics.CMD_TOPIC_CONTROLDEVICE_REPLY, source_payload)
        os_util.reboot(1)
    elseif data.command == 1 then
        -- 远程开门
        log.debug("远程开门")
        dx_gpio.gpio_set_value(GPIO_70, 1)
        os_util.sleep(config.get("openTime"))
        dx_gpio.gpio_set_value(GPIO_70, 0)

        -- 执行回调
        source_payload.code = "000000"
        callback_common(publish_topics.CMD_TOPIC_CONTROLDEVICE_REPLY, source_payload)
        return true
    elseif data.command == 2 or data.command == 3 then
        -- 设备启用/禁用
        if data.command == 2 then
            log.debug("设备启用")
            config.set("deviceStatus", "1")
        elseif data.command == 3 then
            log.debug("设备禁用")
            config.set("deviceStatus", "2")
        end
        -- 持久化配置
        config.config_write_file()
        source_payload.code = "000000"
        log.debug("[setConfig]数据保存成功！ ")
        callback_common(publish_topics.CMD_TOPIC_CONTROLDEVICE_REPLY, source_payload)
        return true
    elseif data.command == 4 then
        -- 设备重置
        log.debug("设备重置")
        os_util.reset()
        source_payload.code = "000000"
        callback_common(publish_topics.CMD_TOPIC_CONTROLDEVICE_REPLY, source_payload)
        os_util.reboot(0)
    end
    return true
end

-- 添加权限
function mqtt_service.insertPermission(payload)
    local ret, data, source_payload = payload_validate(payload)
    if not ret then
        return false
    end
    dx_map.set(_G_map, "mqtt_dog", "Y")
    local ids
    if data and (type(data) == "table") then
        if #data > 200 then
            -- 超出每页最大限额
            source_payload.data = ids
            source_payload.code = "221212"
            callback_common(publish_topics.CMD_TOPIC_INSERTPERMISSION_REPLY, source_payload)
            return false
        end
        ret, ids = t_permission.dx_sqlite_batch_save_whitelists(data)
        if not ret then
            -- 保存出错回调，100000	未知错误
            source_payload.data = ids
            source_payload.code = "100000"
            callback_common(publish_topics.CMD_TOPIC_INSERTPERMISSION_REPLY, source_payload)
            return false
        end
        -- 执行回调
        source_payload.data = ids
        source_payload.code = "000000"
        callback_common(publish_topics.CMD_TOPIC_INSERTPERMISSION_REPLY, source_payload)
        return true
    else
        -- 出错回调，200000	参数异常
        source_payload.data = ids
        source_payload.code = "200000"
        callback_common(publish_topics.CMD_TOPIC_INSERTPERMISSION_REPLY, source_payload)
        return false
    end
end

-- 查询权限
function mqtt_service.getPermission(payload)
    local ret, data, source_payload = payload_validate(payload)
    if not ret then
        return false
    end
    local page = data.page
    local size = data.size
    if (not page) or (not size) then
        -- 参数异常
        source_payload.code = "200000"
        callback_common(publish_topics.CMD_TOPIC_GETPERMSSION_REPLY, source_payload)
        return false
    end
    -- 分页查询
    local ret1, total_count = t_permission.dx_sqlite_total_count_whitelists()
    local ret2, query_rs = t_permission.dx_sqlite_select_whitelists(data)
    if (not ret1) or (not ret2) then
        source_payload.data = nil
    else
        source_payload.data.total = total_count
        source_payload.data.count = #query_rs
        local a, b = math.modf(total_count / size)
        source_payload.data.totalPage = total_count / size
        if b ~= 0 then
            source_payload.data.totalPage = a + 1
        end
        source_payload.data.content = query_rs
    end
    source_payload.code = "000000"
    callback_common(publish_topics.CMD_TOPIC_GETPERMSSION_REPLY, source_payload)
    return true
end

-- 修改权限
function mqtt_service.updatePermission(payload)
    local ret, data, source_payload = payload_validate(payload)
    if not ret then
        return false
    end
    local ids = {}
    if data and (type(data) == "table") then
        for i, v in ipairs(data) do
            -- 遍历更新
            table.insert(ids, v.id)
            local ret = t_permission.dx_sqlite_update_whitelists(v)
            if not ret then
                -- 更新出错回调，100000	未知错误
                source_payload.data = ids
                source_payload.code = "100000"
                callback_common(publish_topics.CMD_TOPIC_UPDATEPERMISSION_REPLY, source_payload)
                return false
            end
        end
        -- 执行回调
        source_payload.data = ids
        source_payload.code = "000000"
        callback_common(publish_topics.CMD_TOPIC_UPDATEPERMISSION_REPLY, source_payload)
        return true
    else
        -- 出错回调，200000	参数异常
        source_payload.data = ids
        source_payload.code = "200000"
        callback_common(publish_topics.CMD_TOPIC_UPDATEPERMISSION_REPLY, source_payload)
        return false
    end
end

-- 删除权限
function mqtt_service.delPermission(payload)
    local ret, data, source_payload = payload_validate(payload)
    if not ret then
        return false
    end
    local ret = t_permission.dx_sqlite_del_whitelists(data)
    if not ret then
        -- 出错回调，100000	未知错误
        source_payload.code = "100000"
        callback_common(publish_topics.CMD_TOPIC_DELPERMISSION_REPLY, source_payload)
        return false
    end
    -- 执行回调
    source_payload.code = "000000"
    callback_common(publish_topics.CMD_TOPIC_DELPERMISSION_REPLY, source_payload)
    return true
end

-- 清空权限
function mqtt_service.clearPermission(payload)
    local ret, data, source_payload = payload_validate(payload)
    if not ret then
        return false
    end
    local ret = t_permission.dx_sqlite_clear_whitelists()
    if not ret then
        -- 出错回调，100000	未知错误
        source_payload.code = "100000"
        source_payload.data = nil
        callback_common(publish_topics.CMD_TOPIC_CLEARPERMISSION_REPLY, source_payload)
        return false
    end
    -- 执行回调

    source_payload.code = "000000"
    source_payload.data = nil
    callback_common(publish_topics.CMD_TOPIC_CLEARPERMISSION_REPLY, source_payload)
    return true
end

-- 通行记录队列消费
function mqtt_service.dx_access(mqtt_msg)
    local de_msg = dx_bit.str_to_tab(mqtt_msg)

    local IdentityCode = de_msg.IdentityCode
    local IdentityType = de_msg.IdentityType
    local permissionId = de_msg.permissionId
    local result = de_msg.result

    if
        not IdentityCode or not IdentityType or not permissionId or IdentityCode == "nil" or IdentityType == "nil" or
            permissionId == "nil"
     then
        callback_common(
            publish_topics.EVENT_TOPIC_ACCESS,
            {
                serialNo = randomStr(10),
                uuid = device_addr,
                data = {
                    {
                        time = os.time(),
                        result = tonumber(result),
                        extra = ""
                    }
                },
                sign = ""
            }
        )
        return false
    end

    local record = {
        id = permissionId,
        code = IdentityCode,
        type = tonumber(IdentityType),
        time = os.time(),
        result = tonumber(result),
        extra = ""
    }
    local record_list = {record}

    local cd_obj = {
        serialNo = randomStr(10),
        uuid = device_addr,
        data = record_list,
        sign = ""
    }

    local ret = t_passrecord.dx_sqlite_save_passrecord(record)

    callback_common(publish_topics.EVENT_TOPIC_ACCESS, cd_obj)
    return true
end

-- 通行记录回调，上送完，pass那边的回调
function mqtt_service.access_reply(payload)
    local ret, data, source_payload = payload_validate(payload)
    if not ret then
        return false
    end
    return true
end

-- 连接上报
function mqtt_service.dx_connect()
    local payload = {
        serialNo = randomStr(10),
        uuid = config.get("uuid"),
        data = {},
        sign = ""
    }
    payload.data.time = os.time()
    payload.data.sysVersion = config.get("sysVersion")
    payload.data.appVersion = config.get("appVersion")
    payload.data.createTime = config.get("createTime")
    payload.data.uuid = config.get("uuid")
    payload.data.name = config.get("deviceName")
    payload.data.model = config.get("model")
    callback_common(publish_topics.EVENT_TOPIC_CONNECT, payload)
    return true
end

-- 连接上报回调，上送完，pass那边的回调
function mqtt_service.connect_reply(payload)
    local ret, data, source_payload = payload_validate(payload)
    if not ret then
        return false
    end
    return true
end

-- 日志上报队列消费
function mqtt_service.dx_log(mqtt_msg)
    local de_msg = dx_bit.str_to_tab(mqtt_msg)
    local cd_obj = {
        serialNo = randomStr(10),
        uuid = device_addr,
        data = {
            level = tonumber(de_msg.level),
            time = tonumber(de_msg.time),
            log = de_msg.log
        },
        sign = ""
    }

    callback_common(publish_topics.EVENT_TOPIC_LOG, cd_obj)
    return true
end

-- 日志上报回调
function mqtt_service.log_reply(payload)
    local ret, data, source_payload = payload_validate(payload)
    if not ret then
        return false
    end
    return true
end

-- 设备信息查询
function mqtt_service.getConfig(payload)
    local ret, data, source_payload = payload_validate(payload)
    if not ret then
        return false
    end
    local result = {}
    -- 网络配置相关
    result.netInfo = {}
    -- 网络类型(0:以太网1:wifi)
    result.netInfo.type = config.get("net_net_type")
    -- wifi名
    result.netInfo.ssid = config.get("net_ssid")
    -- wifi密码
    result.netInfo.pwd = config.get("net_pwd")
    -- 是否为DHCP(0:不是1:是)
    result.netInfo.dhcp = config.get("net_dhcp")
    -- 	ip地址
    result.netInfo.local_ip = config.get("net_local_ip")
    -- 网关
    result.netInfo.local_gateway = config.get("net_local_gateway")
    -- DNS服务器
    result.netInfo.local_dns = config.get("net_local_dns")
    -- 子网掩码
    result.netInfo.local_netmask = config.get("net_local_netmask")

    -- mqtt配置信息
    result.mqtt_info = {}
    -- Mqtt地址（ip）默认开发环境
    result.mqtt_info.mqttAddr = config.get("mqtt_mqttAddr")
    -- Mqtt地址（端口）默认开发环境
    result.mqtt_info.port = config.get("mqtt_port")
    -- 客户端id，与设备地址一致
    result.mqtt_info.clientId = config.get("mqtt_clientId")
    -- mqtt用户名
    result.mqtt_info.mqttName = config.get("mqtt_mqttName")
    -- mqtt密码
    result.mqtt_info.password = config.get("mqtt_password")

    -- 设备基础配置信息
    result.baseInfo = {}
    -- 系统时间
    result.baseInfo.time = config.get("time")
    -- 系统版本号
    result.baseInfo.sysVersion = config.get("sysVersion")
    -- 应用版本号
    result.baseInfo.appVersion = config.get("appVersion")
    -- 应用发布日期
    result.baseInfo.createTime = config.get("createTime")
    -- 设备地址（uuid）
    result.baseInfo.uuid = config.get("uuid")
    -- 设备名称
    result.baseInfo.deviceName = config.get("deviceName")
    -- 	设备类型
    result.baseInfo.model = config.get("model")
    -- 设备基本状态 0-未激活 1-正常 2-禁用
    result.baseInfo.deviceStatus = config.get("deviceStatus")
    -- 权限条数
    local permissionRet, permissionCount = t_permission.dx_sqlite_total_count_whitelists()
    if permissionRet then
        result.baseInfo.permissionCount = permissionCount
    end
    -- 通行记录条数
    local passRecordRet, passRecordCount = t_passrecord.dx_sqlite_query_passrecord_count()
    if passRecordRet then
        result.baseInfo.passRecordCount = passRecordCount
    end

    -- 设备系统资源信息
    result.sysInfo = {}
    -- 设备剩余空间 单位是 kb
    result.sysInfo.cpu = config.get("cpu")
    -- 内存剩余空间 单位是 kb
    result.sysInfo.memroy = config.get("memroy")
    -- CPU 占用比率 %
    result.sysInfo.disk = config.get("disk")

    -- 设备开门相关配置信息
    result.door = {}
    -- 设备开门模式，0-正常，1-常开模式，2-常闭模式
    result.door.mode = config.get("mode")
    -- 开门时长，单位秒
    result.door.openTime = config.get("openTime")

    -- 筛选条件
    local res = {}
    local temp = res
    if data and type(data) == "string" and #data ~= 0 then
        local conditions = string_util.split(data, ".")
        for i, v in ipairs(conditions) do
            result = result[v]
            if #conditions == i then
                temp[v] = result
            else
                temp[v] = {}
            end
            temp = temp[v]
        end
        result = res
    end

    source_payload.data = result
    source_payload.code = "000000"
    log.debug("[getConfig]最终返回给paas的数据：", dx_json.encode(result))

    callback_common(publish_topics.CMD_TOPIC_GETCONFIG_REPLY, source_payload)
    return true
end

-- 告警上报回调
function mqtt_service.alarm_reply(payload)
    log.debug("告警上报回调")
end

-- 告警上报
function mqtt_service.dx_alarm(payload)
    local de_msg = dx_bit.str_to_tab(payload)
    if de_msg == nil then
        return false
    end
    local type = de_msg.type
    local value = de_msg.value

    if not type or not value then
        return false
    end
    local record = {
        type = type,
        value = value
    }

    local cd_obj = {
        serialNo = randomStr(10),
        uuid = device_addr,
        data = record,
        sign = ""
    }
    callback_common(publish_topics.EVENT_TOPIC_ALARM, cd_obj)
    return true
end

-- 设备配置
-- todo 需要paas一起改
function mqtt_service.setConfig(payload)
    local ret, data, source_payload = payload_validate(payload)
    if not ret then
        return false
    end
    -- paas远程配置
    local configData = source_payload.data

    -- 网络配置
    local netInfo = configData.netConfig
    local flag = true
    local count = 0
    if netInfo ~= nil then
        -- 是否为DHCP(1:静态，2:动态)
        config.set("net_dhcp", netInfo.dhcp)
        -- wifi名称
        flag = dx_mapping.getConfigByMapping(netInfo)
        if flag == false then
            count = count + 1
        end
    end

    -- MQTT配置
    local mqttInfo = configData.mqttConfig
    if mqttInfo ~= nil then
        flag = dx_mapping.getConfigByMapping(mqttInfo)
        if flag == false then
            count = count + 1
        end
    end

    -- 基本配置
    local baseInfo = configData.baseConfig
    if baseInfo ~= nil then
        flag = dx_mapping.getConfigByMapping(baseInfo)
        if flag == false then
            count = count + 1
        end
    end

    -- sysInfo 系统配置
    local sysInfo = configData.sysInfo
    if sysInfo ~= nil then
        flag = dx_mapping.getConfigByMapping(sysInfo)
        if flag == false then
            count = count + 1
        end
    end

    -- door 设备开门相关配置信息
    local door = configData.door
    if door ~= nil then
        -- 0-正常
        if door.mode == "1" then
            -- 常开模式
            dx_gpio.gpio_set_value(GPIO_70, 1)
        elseif door.mode == "2" then
            -- 常闭模式
            dx_gpio.gpio_set_value(GPIO_70, 0)
        end

        flag = dx_mapping.getConfigByMapping(door)
        if flag == false then
            count = count + 1
        end
    end
    -- 数据持久化
    config.config_write_file()

    source_payload.code = "000000"
    callback_common(publish_topics.CMD_TOPIC_SETCONFIG_REPLY, source_payload)
    return true
end

function mqtt_service.upgradeFirmware(payload)
    local ret, data, source_payload = payload_validate(payload)
    if not ret then
        return false
    end
    log.debug("[dx_upgrade_firmware]URL: ", data.url)
    log.debug("[dx_upgrade_firmware]md5: ", data.md5)
    local res = dx_download_util.downloadFirmware(data.url, "/vgapp/cc101_app.tar.xz")
    if res == 0 then
        source_payload.code = "000000"
    else
        source_payload.code = "111111"
    end
    config.set("run_status", 2)
    -- 数据持久化
    config.config_write_file()
    callback_common(publish_topics.CMD_TOPIC_UPGRADEFIRMWARE_REPLY, source_payload)
    log.debug("[dx_upgrade_firmware]固件包下载成功，准备重启...... ")
    time.sleep(2)
    os_util.reboot(2)
    return true
end

-------------数据校验-------------
function payload_validate(payload)
    if not payload then
        log.error("mqtt消息为nil")
        return false
    end
    local source_payload = dx_json.decode(payload)
    local serialNo = source_payload.serialNo
    local uuid = source_payload.uuid
    local data = source_payload.data
    local time = source_payload.time
    local sign = source_payload.sign
    local code = source_payload.code

    if (not serialNo) or (not uuid) or (not time) or (not sign) or (not code and not data) then
        -- 校验格式
        log.error("错误的mqtt消息格式")
        return false
    end
    -- 校验uuid
    if uuid ~= device_addr then
        log.error("设备地址不匹配")
        return false
    end
    return true, data, source_payload
end

-------------通用回调-------------
function callback_common(topic, cb_obj)
    cb_obj.time = os.time()
    dx_json.encode(cb_obj)
    -- 避免造成日志上送陷入循环
    if topic ~= publish_topics.EVENT_TOPIC_LOG then
        log.info(topic .. "：" .. dx_json.encode(cb_obj))
    end
    dx_map.set(_G_map, "mqtt_dog", "Y")
    mqtt_client:publish(topic, dx_json.encode(cb_obj))
end

-------------随机生成指定位数的数字和字母的组合-------------
function randomStr(num)
    local key = "abcdefghijklmnopqrstuvwxyz0123456789"
    local str = ""
    local x = 1
    for i = 1, num, 1 do
        -- 产生[n, m]之间的整数
        x = math.random(1, 36)
        str = str .. string.sub(key, x, x)
    end
    return str
end

return mqtt_service
